(function (root, factory, undef) {
    if (typeof exports === 'object') {
        // CommonJS
        module.exports = exports = factory(require('./core'), require('./cipher-core'));
    } else {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['./core', './cipher-core'], factory);
        } else {
            // Global (browser)
            factory(root.CryptoJS);
        }
    }
})(this, function (CryptoJS) {
    /**
     * Counter block mode.
     */
    CryptoJS.mode.CTR = (function () {
        var CTR = CryptoJS.lib.BlockCipherMode.extend();
        var Encryptor = (CTR.Encryptor = CTR.extend({
            processBlock: function (words, offset) {
                // Shortcuts
                var cipher = this._cipher;
                var blockSize = cipher.blockSize;
                var iv = this._iv;
                var counter = this._counter; // Generate keystream

                if (iv) {
                    counter = this._counter = iv.slice(0); // Remove IV for subsequent blocks

                    this._iv = undefined;
                }

                var keystream = counter.slice(0);
                cipher.encryptBlock(keystream, 0); // Increment counter

                counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0; // Encrypt

                for (var i = 0; i < blockSize; i++) {
                    words[offset + i] ^= keystream[i];
                }
            }
        }));
        CTR.Decryptor = Encryptor;
        return CTR;
    })();

    return CryptoJS.mode.CTR;
});
